/**
 * Created with JetBrains WebStorm.
 * User: Steven
 * Date: 27-4-13
 * Time: 21:00
 * To change this template use File | Settings | File Templates.
 */

function CharacterController($scope, $http)
{
    $scope.races = Race.races;
    $scope.birthsigns = Birthsign.birthsigns;
    $scope.classes = Class.classes;
    $scope.character = null;

    // Pre-made selections
    $scope.selectedRace = null;
    $scope.selectedBirthsign = null;
    $scope.selectedClass = null;

    // Custom class fields
    // Specialization with workaround for radio buttons: https://github.com/angular/angular.js/issues/1100
    $scope.selectedSpecialization = { spec: CombatSpecialization }; // Default is Combat

    // Focus attributes
    $scope.focusAttributeOne = null;
    $scope.focusAttributeTwo = null;

    // Misc
    $scope.lastSync = "Never";

    $scope.init = function()
    {
        // Load the Character if a key is available
        var characterKey = $scope.getUrlVars()["key"];
        if(characterKey != null)
        {
            $scope.loadCharacter(characterKey);
        }
    };

    // Credits: http://papermashup.com/read-url-get-variables-withjavascript/
    $scope.getUrlVars = function() {
        var vars = {};
        var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
            vars[key] = value;
        });
        return vars;
    };

    $scope.refreshSyncDate = function()
    {
        var currentTime = new Date();
        var year = currentTime.getFullYear();
        var month = currentTime.getMonth() + 1;
        var day = currentTime.getDate();

        var hours = currentTime.getHours();
        var minutes = currentTime.getMinutes();
        var seconds = currentTime.getSeconds();

        var date = year + "/"
            + (month < 10 ? "0" : "") + month + "/"
            + (day < 10 ? "0" : "") + day;

        var time = (hours < 10 ? "0" : "") + hours + ":"
            + (minutes < 10 ? "0" : "") + minutes + ":"
            + (seconds < 10 ? "0" : "") + seconds;

        $scope.lastSync = date + " " + time;
    };

    $scope.createCharacter = function()
    {
        var race = $scope.selectedRace;
        var birthsign = $scope.selectedBirthsign;
        var characterClass = $scope.getClass();

        if(race == null || birthsign == null || characterClass == null)
        {
            alert("Please select a race, a birthsign and a (valid custom) class before trying to create a character.");
            return;
        }

        // Create the Character, and link the level-up event
        $scope.character = new Character(Gender.male, new race, new birthsign, characterClass);
        $scope.linkLevelUpEvent($scope.character);
        //$scope.character.levelUpEvent = function(leveledSkills) { $scope.onCharacterLevelUp(leveledSkills); };

        // Reset radio buttons to default
        $scope.selectedSpecialization.spec = CombatSpecialization;

        // Save the Character to the database
        $scope.saveCharacter();
    };

    $scope.linkLevelUpEvent = function(character)
    {
        character.levelUpEvent = function(leveledSkills) { $scope.onCharacterLevelUp(leveledSkills); };
    };

    $scope.saveCharacter = function()
    {
        // Encode the Character to JSON
        var jsonCharacter = $scope.character.toJSON();

        // POST the new Character
        $.ajax({
            url: "database/CharacterController.php",
            method: "POST",
            data: { action: "create", character: jsonCharacter }
        }).done(function(data) {
            $scope.$apply(function() {
                alert("Your character has been saved. ID: " + data);
                $scope.character.key = data;
                $scope.refreshSyncDate();
            });
        }).error(function(data) {
            $scope.$apply(function() {
                alert("Error saving character: \n\n" + data);
                $scope.character.id = -1;
                $scope.character.key = "unknown";
            });
        });

        // AngularJS POST disabled due to header compatibility problems with PHP.
        // TODO: Look into header complications, so that $http can be used for posting.
        //
        // Extra information:
        // http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

//        $http({
//            url: "database/CharacterController.php",
//            method: "GET",
//            params: { "action": "create", character: jsonCharacter }
//            /*headers: {'Content-Type': 'application/json'}*/
//        }).success(function(data, status, headers, config) {
//                alert("Your character has been saved. ID: " + data);
//        }).error(function(data, status, headers, config) {
//            alert("Error saving character: \n\n" + data);
//        });
        //console.debug(jsonCharacter);
    };

    $scope.loadCharacter = function(key)
    {
        /*
         * AJAX is done via JQuery for now, due to a caching problem with Internet Explorer. For some reason,
         * the "cache: false" in the $http function doesn't seem to work, even though the documentation states
         * that it should. As a temporary solution, JQuery will handle the AJAX for now.
         *
         * TODO: Find a solution to the caching problem when loading a Character via AngularJS $html.
         */

        // Load the Character
        $.ajax({
            url: "database/CharacterController.php",
            method: "GET",
            data: { action: "load", key: key },
            cache: false
        }).done(function(data) {
            $scope.$apply(function() {
                $scope.character = $scope.parseCharacter(data);
                $scope.refreshSyncDate();
                $scope.updateLevelProgressBar();
                alert("Your character has been loaded.");
                var tabs = $("#tabs");
                tabs.tabs("option", "active", 2);
            });
        }).error(function(data) {
            alert("Error loading character: \n\n" + data.responseText);
            //console.debug(data);
        });

//        $http({
//            url: "database/CharacterController.php",
//            method: "GET",
//            params: { action: "load", id: id },
//            cache: false
//        }).success(function(data, status, headers, config) {
//                $scope.character = $scope.parseCharacter(data);
//                $scope.refreshSyncDate();
//                $scope.updateLevelProgressBar();
//                alert("Your character has been loaded.");
//        }).error(function(data, status, headers, config) {
//                alert("Error loading character: \n\n" + data);
//        });
    };

    $scope.parseCharacter = function(rawCharacter)
    {
        var genderKey = Object.keys(Gender)[rawCharacter.gender];
        var gender = Gender[genderKey];
        var race = new Race.races[rawCharacter.race];
        var birthsign = new Birthsign.birthsigns[rawCharacter.birthsign];

        var characterClass = null;
        if(rawCharacter.class > 0)
        {
            characterClass = new Class.classes[rawCharacter.class];
        }
        else
        {
            // Extract the custom Class
            var customClass = rawCharacter.customClass;

            // Fetch class information from the custom class
            var className = customClass.name;
            var specialization = new Specialization.specializations[customClass.specialization];
            var favoredAttributeOneKey = Object.keys(AttributeTypes)[customClass.favoredAttributeOne];
            var favoredAttributeTwoKey = Object.keys(AttributeTypes)[customClass.favoredAttributeTwo];
            var favoredAttributeOne = AttributeTypes[favoredAttributeOneKey];
            var favoredAttributeTwo = AttributeTypes[favoredAttributeTwoKey];

            // Create the custom class
            characterClass = new Class(className, specialization);
            characterClass.favoredAttributeOne = favoredAttributeOne;
            characterClass.favoredAttributeTwo = favoredAttributeTwo;

            // Add major skills to the custom class
            var rawSkills = customClass.majorSkills.split(","); // Comma-separated
            for(var i = 0; i < rawSkills.length; i++)
            {
                var skillTypeKey = Object.keys(SkillTypes)[rawSkills[i]];
                var skillType = SkillTypes[skillTypeKey];
                characterClass.addMajorSkillType(skillType);
            }
        }

        // Create the Character
        var character = new Character(gender, race, birthsign, characterClass);

        // Apply Skill progress
        var skillSet = rawCharacter.skillSet;
        var skillTypeKeys = Object.keys(skillSet);
        for(var i = 0; i < skillTypeKeys.length; i++)
        {
            // Fetch the Skill
            var skillTypeKey = skillTypeKeys[i];
            var skillType = SkillTypes[skillTypeKey];
            var skill = character.skillSet.getSkill(skillType);
            if(skill == null)
                continue;

            // Apply the Skill level and progress level
            var skillProgress = skillSet[skillTypeKey].split(",");
            var skillLevel = skillProgress[0];
            var skillProgressLevel = skillProgress[1];
            skill.level = parseInt(skillLevel);
            skill.progressLevel = parseInt(skillProgressLevel);
        }

        // Apply attribute progress
        var attributeSet = rawCharacter.attributeSet;
        var attributeTypeKeys = Object.keys(attributeSet);
        for(var i = 0; i < attributeTypeKeys.length; i++)
        {
            // Fetch the Attribute
            var attributeTypeKey = attributeTypeKeys[i];
            var attributeType = AttributeTypes[attributeTypeKey];
            var attribute = character.attributeSet.getAttribute(attributeType);
            if(attribute == null)
                continue;

            // Apply the attribute level
            attribute.level = parseInt(attributeSet[attributeTypeKey]);
        }

        // Bind the level-up event and set the ID of the Character
        //character.levelUpEvent = function(leveledSkills) { $scope.onCharacterLevelUp(leveledSkills); };
        $scope.linkLevelUpEvent(character);
        character.id = parseInt(rawCharacter["id"]);
        character.key = rawCharacter["key"];

        // Return the new character
        return character;
    };

    $scope.modifySkill = function(skill)
    {
        var skillTypeKey = skill.skillTypeKey;
        var skillStats = skill.level + "," + skill.progressLevel;

        $.ajax({
            url: "database/CharacterController.php",
            method: "POST",
            data:
            {
                action: "modifyskill",
                characterKey: $scope.character.key,
                skillType: skillTypeKey,
                skillStats: skillStats
            }
        }).done(function(data) {
            $scope.$apply(function(){
                $scope.refreshSyncDate();
                //console.debug(data);
            });
        }).error(function(data) {
            var errorMsg = "Error changing skill stats. Please try again later. Sorry!\n\n"
                + "Encountered error:\n" +data.responseText;
            alert(errorMsg);
        });
    };

    $scope.modifyAttribute = function(attribute)
    {
        var attributeTypeKey = attribute.attributeTypekey;

        $.ajax({
            url: "database/CharacterController.php",
            method: "POST",
            data:
            {
                action: "modifyattribute",
                characterKey: $scope.character.key,
                attributeType: attributeTypeKey,
                attributeLevel: attribute.level
            }
        }).done(function(data) {
            $scope.$apply(function(){
                $scope.refreshSyncDate();
                //console.debug(data);
            });
        }).error(function(data) {
            var errorMsg = "Error changing attribute stats. Please try again later. Sorry!\n\n"
                + "Encountered error:\n" +data.responseText;
            alert(errorMsg);
        });
    };

    $scope.getCharacterLevel = function()
    {
        return $scope.character.calculateLevel();
    };

    $scope.updateLevelProgressBar = function()
    {
        $( "#levelProgressBar" ).progressbar({
            value: $scope.character.calculateLevelProgress()
        });
    };

    $scope.onCharacterLevelUp = function(leveledSkills)
    {
        // Synchronize the Skills that have been leveled
        var skillProgressList = {};
        for(var i = 0; i < leveledSkills.length; i++)
        {
            var skill = leveledSkills[i];
            skillProgressList[skill.skillTypeKey] = skill.level + "," + skill.progressLevel;
        }

        // JSON-Encode the skill progress list
        var encodedSkillProgressList = JSON.stringify(skillProgressList);

        // Send the modified skills
        $.ajax({
            url: "database/CharacterController.php",
            method: "POST",
            data:
            {
                action: "modifyskills",
                characterKey: $scope.character.key,
                skills: encodedSkillProgressList
            }
        }).done(function(data) {
            $scope.$apply(function(){
                $scope.refreshSyncDate();
            });
        }).error(function(data) {
            var errorMsg = "Error synching the skills that were leveled up. Please try again later. Sorry!"
                + "\n\nReason:\n" + data.responseText;
            alert(errorMsg);
        });

        alert("Congratulations, you've just leveled up!");
    };

    /*
     * Skill related functions
     */

    $scope.enableSkillModification = function()
    {
        $(".statProgress").removeAttr("disabled");
    };

    $scope.disableSkillModification = function()
    {
        $(".statProgress").attr("disabled","disabled");
        //console.debug($(".statProgress"));
    };

    $scope.getSkills = function()
    {
        $scope.ensureCharacterExistance();
        return $scope.character.skillSet.getSkills();
    };

    $scope.getSelectedSkills = function()
    {
        var selectedSkills = [];
        var skills = $scope.getSkills();
        for(var i = 0; i < skills.length; i++)
        {
            if(skills[i].checked)
                selectedSkills.push(skills[i]);
        }
        return selectedSkills;
    };

    $scope.getSkillProgress = function(skill)
    {
        var progressDom = "";
        var progressString = "";

        // Determine the progress string
        if(skill.progressLevel > 0)
            progressString = "(" + skill.progressLevel + "/10)";

        // Determine whether the skill has been overleveled or not
        if(skill.progressLevel > 10)
            progressDom = "<span class='skillProgressOverleved'>" + progressString + "</span>";
        else
            progressDom = "<span class='skillProgress'>" + progressString + "</span>";

        // Return the DOM string
        return progressDom;
    };

    $scope.getSkillNameClass = function($skill)
    {
        if($skill.isMajor())
            return "skillNameMajor";
        return "skillName";
    };

    $scope.adjustSkillLevel = function($skill, $value)
    {
        $skill.adjustLevel($value);
        $scope.modifySkill($skill); // Synchronize with the database
    };

    $scope.adjustSkillProgressLevel = function($skill, $value)
    {
        // Make sure the progress level isn't negative, otherwise the user could level the skill down
        if($skill.progressLevel + $value < 0)
            return;

        $skill.adjustProgressLevel($value);
        $scope.modifySkill($skill); // Synchronize with the database
        $scope.updateLevelProgressBar();
    };

    /*
     * Attribute related functions
     */

    $scope.getAttributes = function()
    {
        $scope.ensureCharacterExistance();
        return $scope.character.attributeSet.getAttributes();
    };

    $scope.getAttributeProgress = function(attribute)
    {
        var progressDom = "";
        var progressString = "";
        var progress = attribute.getProgress();
        var progressAttributePoints = 0;

        // Determine the attribute skill points
        if(progress >= 1 && progress <= 4)
            progressAttributePoints = 2;
        else if(progress >= 5 && progress <= 7)
            progressAttributePoints = 3;
        else if(progress >= 8 && progress <= 9)
            progressAttributePoints = 4;
        else if(progress >= 10)
            progressAttributePoints = 5;

        // Create the progress string
        if(progressAttributePoints > 0)
            progressString += "+" + progressAttributePoints + " points<br/>";
        progressString += "(" + progress + "/10)";

        // Determine the style
        if(progress > 0 && progress <= 10)
        {
            if(attribute == $scope.focusAttributeOne || attribute == $scope.focusAttributeTwo)
                progressDom = "<span class='attributeProgress'>" + progressString + "</span>";
            else
                progressDom = "<span class='attributeProgressNonFocus'>" + progressString + "</span>";
        }
        else if(progress > 10)
            progressDom = "<span class='attributeProgressOverleveled'>" + progressString + "</span>";
        else
            progressDom = "<span>" + progressString + "</span>";

        // Return the DOM string
        return progressDom;
    };

    $scope.getSelectedAttributes = function()
    {
        var attributes = $scope.getAttributes();
        var selectedAttributes = [];
        for(var i = 0; i < attributes.length; i++)
        {
            if(attributes[i].checked)
                selectedAttributes.push(attributes[i]);
        }
        return selectedAttributes;
    };

    $scope.adjustAttributeLevel = function(attribute, value)
    {
        attribute.level += value;
        $scope.modifyAttribute(attribute); // Sync with the database
    };

    /*
     * Class related functions
     */

    $scope.verifyCustomClassSettings = function()
    {
        var selectedSpecialization = $scope.selectedSpecialization.spec;
        var selectedAttributes = $scope.getSelectedAttributes();
        var selectedSkills = $scope.getSelectedSkills();

        if(selectedSpecialization == null)
            return "Specialization missing. Please select a specialization.";
        else if(selectedAttributes.length != 2)
            return "Please select two favored attributes (you've selected " + selectedAttributes.length + "/2).";
        else if(selectedSkills.length != 7)
            return "Please select exactly 7 major skills (you've selected " + selectedSkills.length + "/7).";
        else
            return "All custom class settings are valid.";
    };

    $scope.isCustomClassValid = function()
    {
        var selectedSpecialization = $scope.selectedSpecialization.spec;
        var selectedAttributes = $scope.getSelectedAttributes();
        var selectedSkills = $scope.getSelectedSkills();
        return selectedSpecialization != null && selectedAttributes.length == 2 && selectedSkills.length == 7;
    };

    $scope.getClass = function()
    {
        if($scope.isCustomClassValid())
        {
            var selectedSpecialization = $scope.selectedSpecialization.spec;
            var selectedAttributes = $scope.getSelectedAttributes();
            var selectedSkills = $scope.getSelectedSkills();

            var customClass = new Class("Custom", new selectedSpecialization);
            customClass.favoredAttributeOne = selectedAttributes[0].attributeType;
            customClass.favoredAttributeTwo = selectedAttributes[1].attributeType;
            for(var i = 0; i < selectedSkills.length; i++)
            {
                customClass.addMajorSkillType(selectedSkills[i].skillType);
            }
            return customClass;
        }
        else
        {
            return $scope.selectedClass != null ? new $scope.selectedClass : null;
        }
    };

    $scope.getClassSkills = function()
    {
        var majorSkills = "";
        var majorSkillTypes = $scope.character.class.getMajorSkillTypes();
        for(var i = 0; i < majorSkillTypes.length; i++)
        {
            majorSkills += majorSkillTypes[i] + ", ";
        }
        return majorSkills;
    };

    $scope.ensureCharacterExistance = function()
    {
        if($scope.character == null)
        {
            // Temporary default character for testing
            $scope.character = new Character(Gender.male, new Nord(), new LadyBirthsign(), new Acrobat());
            //$scope.character.levelUpEvent = function() { $scope.onCharacterLevelUp(); };
            $scope.linkLevelUpEvent($scope.character);
        }
    };

    $scope.getSpecializations = function()
    {
        return Specialization.specializations;
    };

    $scope.specHasSkillMod = function(skill)
    {
        // TODO: Construct a better way of adding and reading skill modifiers from/to a Specialization!
        var selectedSpec = new $scope.selectedSpecialization.spec;
        return selectedSpec.hasSkillModifier(skill.skillType);
    };

    // Initialize the controller
    $scope.init();
}
